//Syntax:  chain_calling 
//      1. fn(&self) -> &Self { self }
//      2. fn(&mut self) -> &mut Self { self}
//
//Syntax: Singleton: static var-impl
//          Static var = const_context; // const struct, const tuple, const function
//          Static mut var must be in unsafe scope, details see: expect_mut and expect in TracerFactory


#[derive(Debug, PartialEq)]
struct Tracer {
    content:  String,
}

impl Default for Tracer {
    fn default() -> Self {
        Tracer {content : String::default()}
    }
}

impl Tracer {
    pub const fn new() -> Self {
        Tracer { content: String::new() }
    }

    pub fn reset(&mut self) -> &mut Self {
        self.content.clear();
        self
    }

    pub fn dtor(&mut self) -> &mut Self {
        self.append_sep().append_str("dtor")
    }
    pub fn method(&mut self, name: &str) -> &mut Self {
        self.append_sep().append_str(name)
    }
    pub fn operation(&mut self, op_name: &str) -> &mut Self {
        self.append_sep().append_str(op_name)
    }

    pub fn to_string(&self) -> String {
        self.content.clone()
    }

    fn append_sep(&mut self) -> &mut Self {
        self.append_char(':')
    }

    fn append_char(&mut self, ch: char) -> &mut Self {
        self.content.push(ch);
        self
    }
    fn append_str(&mut self, text: &str) ->&mut Self {
        self.content.push_str(text);
        self
    }
}

// Example for Singleton
struct TracerFactory {
}
impl TracerFactory {
    pub unsafe fn expect_mut() -> &'static mut Tracer{
        static mut EXPECT: Tracer = Tracer::new();
        return &mut EXPECT;
    }
    pub fn expect() -> &'static Tracer {
        static EXPECT: Tracer = Tracer::new();
        return &EXPECT;
    }
}


#[cfg(test)]
mod test {
    use super::*;

    #[test]
    fn  test_tracer_factory(){
        unsafe {
            TracerFactory::expect_mut().reset();
        }
        TracerFactory::expect();
        
    }

    #[test]
    fn test_equal(){
        assert_eq!(Tracer::new(), Tracer::new());
        assert_eq!(Tracer::default(), Tracer::default());
    }
    #[test]
    fn test(){
        let mut t = Tracer::default();
        assert_eq!("".to_owned(), t.to_string());

        t.method("hello");
        assert_eq!(":hello".to_owned(), t.to_string());

        t.reset();
        assert_eq!("".to_owned(), t.to_string());

        t.reset().operation("start");
        assert_eq!(":start".to_owned(), t.to_string());

        t.reset().dtor();
        assert_eq!(":dtor".to_owned(), t.to_string());
    }

}
